#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/select.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <sys/prctl.h>

#include "sample_comm.h"
#include "hi_ext_util.h"
#include "plug_media_photomng.h"
#include "plug_media_ao.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */

typedef struct tagPLUG_MEDIA_VPSSCFG_S
{
    HI_S32 s32VpssGrp;
    HI_S32 s32VpssChn;
    VPSS_GRP_ATTR_S stGrpAttr;
    VPSS_CHN_ATTR_S stChnAttr;
}PLUG_MEDIA_VPSSCFG_S;

typedef struct tagPLUG_MEDIA_VENCCFG_S
{
    HI_S32 s32VencChn;
    VENC_CHN_ATTR_S stChnAttr;
}PLUG_MEDIA_VENCCFG_S;


static HI_S32 RECORDMNG_SavePic(HI_CHAR* pazFilePath, VENC_STREAM_S* pstStream)
{
    if (HI_NULL == pazFilePath || HI_NULL == pstStream)
    {
        LOGI("Input null\n");
        return HI_FAILURE;
    }
    HI_S32 i;
    FILE* pFd = HI_NULL;

    pFd = fopen(pazFilePath, "wb");
    if (HI_NULL == pFd)
    {
        LOGE("open file %s filed\n", pazFilePath);
        return HI_FAILURE;
    }

    for (i = 0; i < pstStream->u32PackCount; i++)
    {
        fwrite(pstStream->pstPack[i].pu8Addr + pstStream->pstPack[i].u32Offset,
               pstStream->pstPack[i].u32Len - pstStream->pstPack[i].u32Offset, 1, pFd);

        fflush(pFd);
    }

    fclose(pFd);

    return HI_SUCCESS;
}

static HI_S32 PHOTOMNG_GetVpssCfg(PLUG_MEDIA_VPSSCFG_S *pstVpssCfg)
{
    pstVpssCfg->s32VpssGrp = 0;
    pstVpssCfg->s32VpssChn = 1;

    memset(&pstVpssCfg->stGrpAttr, 0, sizeof(VPSS_GRP_ATTR_S));
    memset(&pstVpssCfg->stChnAttr, 0, sizeof(VPSS_CHN_ATTR_S));
    HI_MPI_VPSS_GetGrpAttr(pstVpssCfg->s32VpssGrp, &pstVpssCfg->stGrpAttr);
    HI_MPI_VPSS_GetChnAttr(pstVpssCfg->s32VpssGrp, pstVpssCfg->s32VpssChn, &pstVpssCfg->stChnAttr);

    return HI_SUCCESS;
}

static HI_S32 PHOTOMNG_GetVencCfg(PLUG_MEDIA_VENCCFG_S *pstVencCfg)
{
    pstVencCfg->s32VencChn = 6;

    /* venc attr */
    memset(&pstVencCfg->stChnAttr, 0, sizeof(VENC_CHN_ATTR_S));
    pstVencCfg->stChnAttr.stVencAttr.enType          = PT_JPEG;
    pstVencCfg->stChnAttr.stVencAttr.u32MaxPicWidth  = 1920;
    pstVencCfg->stChnAttr.stVencAttr.u32MaxPicHeight = 1080;
    pstVencCfg->stChnAttr.stVencAttr.u32PicWidth     = 1920;/*the picture width*/
    pstVencCfg->stChnAttr.stVencAttr.u32PicHeight    = 1080;/*the picture height*/
    pstVencCfg->stChnAttr.stVencAttr.u32BufSize      = 3840 * 2160 * 3;/*stream buffer size*/
    pstVencCfg->stChnAttr.stVencAttr.u32Profile      = 0;
    pstVencCfg->stChnAttr.stVencAttr.bByFrame        = HI_TRUE;/*get stream mode is slice mode or frame mode?*/
    pstVencCfg->stChnAttr.stVencAttr.stAttrJpege.bSupportDCF = HI_FALSE;
    pstVencCfg->stChnAttr.stVencAttr.stAttrJpege.enReceiveMode = VENC_PIC_RECEIVE_SINGLE;
    pstVencCfg->stChnAttr.stVencAttr.stAttrJpege.stMPFCfg.u8LargeThumbNailNum = 0;

    return HI_SUCCESS;
}

static HI_S32 PHOTOMNG_VencInit(PLUG_MEDIA_VENCCFG_S *pstVencCfg)
{
    HI_S32 s32Ret = HI_SUCCESS;
    VENC_CHN s32VencChn = pstVencCfg->s32VencChn;
    VENC_RECV_PIC_PARAM_S stRecvParam;

    s32Ret = HI_MPI_VENC_CreateChn(s32VencChn, &pstVencCfg->stChnAttr);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("HI_MPI_VENC_CreateChn [%d] faild with %#x! ===\n", \
                   s32VencChn, s32Ret);
        return s32Ret;
    }

    LOGI("VENC[%d] started\n", s32VencChn);

    return HI_SUCCESS;
}


HI_S32 PLUG_MEDIA_PHOTOMNG_Init(PLUG_MEDIA_PHOTOMNG_INITCFG_S *pstInitCfg)
{
    //初始化媒体通道，参数目前为空，默认写死
    HI_S32 s32Ret = HI_SUCCESS;
    PLUG_MEDIA_VPSSCFG_S stVpssCfg = { 0 };
    PLUG_MEDIA_VENCCFG_S stVencCfg = { 0 };
    s32Ret = PHOTOMNG_GetVpssCfg(&stVpssCfg);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PHOTOMNG_GetVpssCfg failed\n");
        return HI_FAILURE;
    }

    s32Ret = PHOTOMNG_GetVencCfg(&stVencCfg);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PHOTOMNG_GetVencCfg failed\n");
        return HI_FAILURE;
    }

    s32Ret = PHOTOMNG_VencInit(&stVencCfg);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PLUG_MEDIA_VencInit failed\n");
        return HI_FAILURE;
    }

    s32Ret = SAMPLE_COMM_VPSS_Bind_VENC(stVpssCfg.s32VpssGrp, stVpssCfg.s32VpssChn, stVencCfg.s32VencChn);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("SAMPLE_COMM_VPSS_Bind_VENC vpssgrp %d, vpsschn %d, venc chn %d failed for %#x!\n",
            stVpssCfg.s32VpssGrp, stVpssCfg.stChnAttr, stVencCfg.s32VencChn, s32Ret);
        return HI_FAILURE;
    }

    return HI_SUCCESS;
}

HI_S32 PLUG_MEDIA_PHOTOMNG_TakePhoto(PLUG_MEDIA_PHOTOMNG_CFG_S *pstPhotoCfg)
{
    if (HI_NULL == pstPhotoCfg)
    {
        LOGE("Input is null\n");
    }
    //从venc获取一张图片保存到指定路径
    HI_S32 s32Ret = HI_SUCCESS;
    VENC_RECV_PIC_PARAM_S stRecvParam = { 0 };
    PLUG_MEDIA_VENCCFG_S stVencCfg = { 0 };
    struct timeval TimeoutVal;
    fd_set read_fds;
    HI_S32 s32VencFd;
    VENC_CHN_STATUS_S stStat;
    VENC_STREAM_S stStream;
    HI_U32 i;

    s32Ret = PHOTOMNG_GetVencCfg(&stVencCfg);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PHOTOMNG_GetVencCfg failed\n");
        return HI_FAILURE;
    }

    stRecvParam.s32RecvPicNum = 1;
    s32Ret = HI_MPI_VENC_StartRecvFrame(stVencCfg.s32VencChn, &stRecvParam);
    if (HI_SUCCESS != s32Ret)
    {
        SAMPLE_PRT("HI_MPI_VENC_StartRecvPic faild with%#x!\n", s32Ret);
        return HI_FAILURE;
    }
    /******************************************
     recv picture
    ******************************************/
    s32VencFd = HI_MPI_VENC_GetFd(stVencCfg.s32VencChn);
    if (s32VencFd < 0)
    {
        SAMPLE_PRT("HI_MPI_VENC_GetFd faild with%#x!\n", s32VencFd);
        return HI_FAILURE;
    }

    FD_ZERO(&read_fds);
    FD_SET(s32VencFd, &read_fds);
    TimeoutVal.tv_sec  = 10;
    TimeoutVal.tv_usec = 0;
    s32Ret = select(s32VencFd + 1, &read_fds, NULL, NULL, &TimeoutVal);
    if (s32Ret < 0)
    {
        SAMPLE_PRT("snap select failed!\n");
        return HI_FAILURE;
    }
    else if (0 == s32Ret)
    {
        SAMPLE_PRT("snap time out!\n");
        //return HI_FAILURE;
    }
    else
    {
        if (FD_ISSET(s32VencFd, &read_fds))
        {
            s32Ret = HI_MPI_VENC_QueryStatus(stVencCfg.s32VencChn, &stStat);
            if (s32Ret != HI_SUCCESS)
            {
                SAMPLE_PRT("HI_MPI_VENC_QueryStatus failed with %#x!\n", s32Ret);
                return HI_FAILURE;
            }

            if (0 == stStat.u32CurPacks)
            {
                SAMPLE_PRT("NOTE: Current  frame is NULL!\n");
                return HI_SUCCESS;
            }
            stStream.pstPack = (VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
            if (NULL == stStream.pstPack)
            {
                SAMPLE_PRT("malloc memory failed!\n");
                return HI_FAILURE;
            }
            stStream.u32PackCount = stStat.u32CurPacks;
            s32Ret = HI_MPI_VENC_GetStream(stVencCfg.s32VencChn, &stStream, -1);
            if (HI_SUCCESS != s32Ret)
            {
                SAMPLE_PRT("HI_MPI_VENC_GetStream failed with %#x!\n", s32Ret);

                free(stStream.pstPack);
                stStream.pstPack = NULL;
                return HI_FAILURE;
            }

            s32Ret = RECORDMNG_SavePic(pstPhotoCfg->azFilePath, &stStream);
            if (HI_SUCCESS != s32Ret)
            {
                SAMPLE_PRT("save snap picture failed!\n");

                free(stStream.pstPack);
                stStream.pstPack = NULL;

                return HI_FAILURE;
            }

            s32Ret = HI_MPI_VENC_ReleaseStream(stVencCfg.s32VencChn, &stStream);
            if (HI_SUCCESS != s32Ret)
            {
                SAMPLE_PRT("HI_MPI_VENC_ReleaseStream failed with %#x!\n", s32Ret);

                free(stStream.pstPack);
                stStream.pstPack = NULL;

                return HI_FAILURE;
            }

            free(stStream.pstPack);
            stStream.pstPack = NULL;
        }
    }

    /* stop recv picture */
    s32Ret = HI_MPI_VENC_StopRecvFrame(stVencCfg.s32VencChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("HI_MPI_VENC_StopRecvPic failed with %#x!\n",  s32Ret);
        return HI_FAILURE;
    }

    s32Ret = PLUG_MEDIA_AO_SystemSound(PLUG_MEDIA_AO_SOUND_PHOTO);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PLUG_MEDIA_AO_SystemSound failed\n");
    }

    return HI_SUCCESS;
}

HI_S32 PLUG_MEDIA_PHOTOMNG_Deinit(HI_VOID)
{
    //去初始化媒体通道
    HI_S32 s32Ret = HI_SUCCESS;
    PLUG_MEDIA_VPSSCFG_S stVpssCfg = { 0 };
    PLUG_MEDIA_VENCCFG_S stVencCfg = { 0 };
    s32Ret = PHOTOMNG_GetVpssCfg(&stVpssCfg);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("PHOTOMNG_GetVpssCfg failed\n");
    }

    s32Ret = PHOTOMNG_GetVencCfg(&stVencCfg);
    if (HI_SUCCESS != s32Ret)
    {
        LOGE("RECORDMNG_GetVencCfg failed\n");
    }

    s32Ret = SAMPLE_COMM_VPSS_UnBind_VENC(stVpssCfg.s32VpssGrp, stVpssCfg.s32VpssChn, stVencCfg.s32VencChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("SAMPLE_COMM_VENC_Stop failed with %#x!\n", s32Ret);
    }

    s32Ret= SAMPLE_COMM_VENC_Stop(stVencCfg.s32VencChn);
    if (s32Ret != HI_SUCCESS)
    {
        SAMPLE_PRT("SAMPLE_COMM_VENC_Stop failed with %#x!\n", s32Ret);
    }

    return HI_SUCCESS;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */

